import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { isoToYYYYMMDDHHmmss, transformToOption } from 'src/utils';
import { CreateRoleDto } from './dto/create-role.dto';
import { FindAllRoleDto } from './dto/find-all-role.dto';

@Injectable()
export class RoleService {
  constructor(private prisma: PrismaService) {}
  /**
   * 此 TypeScript 函数在检查是否已存在同名角色后创建一个新角色。
   * @param {CreateRoleDto} body - 您提供的 `create` 函数是一个异步函数，它接受 `CreateRoleDto` 类型的参数 `body`。此函数首先使用
   * Prisma 检查数据库中是否已存在与 `body.name` 同名的角色。如果存在同名的角色，则
   * @returns `create` 函数返回使用 `prisma` 客户端根据提供的 `body` 数据创建新角色的结果。
   */
  async create(body: CreateRoleDto) {
    const existing = await this.prisma.role.findFirst({
      where: { name: body.name },
    });

    if (existing) {
      throw new Error('角色已经存在');
    }

    return this.prisma.role.create({
      data: body,
    });
  }

  /**
   * 此 TypeScript 函数使用 Prisma 客户端根据查询对象异步查找角色，包括分页和格式化时间戳。
   * @param {FindAllRoleDto} query - 您提供的 `findAll` 函数是一个异步函数，它根据提供的查询参数检索角色列表。以下是该函数中使用的参数的细分：
   * @returns `findAll` 函数返回一个具有两个属性的对象：`list` 和 `total`。`list` 属性包含具有选定字段的用户对象数组，其中 `createTime` 和
   * `updateTime` 字段使用 `isoToYYYYMMDDHHmmss` 函数格式化。`total` 属性包含符合查询条件的用户总数。
   */
  async findAll(query: FindAllRoleDto) {
    try {
      // 构建查询条件
      const queryWhere = {
        name: {
          contains: query.keywords,
        },
      };
      // 使用Prisma客户端进行事务查询，同时获取用户列表和总数
      const [roles, count] = await Promise.all([
        this.prisma.role.findMany({
          where: queryWhere,
          orderBy: {
            id: 'desc',
          },
          skip: (query.pageNum - 1) * query.pageSize,
          take: query.pageSize,
          select: {
            id: true,
            name: true,
            status: true,
            code: true,
            sort: true,
            createTime: true,
            updateTime: true,
          },
        }),
        this.prisma.role.count({
          where: queryWhere,
        }),
      ]);

      const roleList = roles.map((role) => {
        return {
          ...role,
          createTime: isoToYYYYMMDDHHmmss(role.createTime),
          updateTime: isoToYYYYMMDDHHmmss(role.updateTime),
        };
      });

      return {
        list: roleList,
        total: count,
      };
    } catch (error) {
      throw new Error(`Error finding roles: ${error.message}`);
    }
  }

  /**
   * 此 TypeScript 函数根据提供的 ID 和数据使用 Prisma 更新数据库中的角色。
   * @param {number} id - `id` 参数是一个数字，代表要在数据库中更新的角色的唯一标识符。
   * @param {CreateRoleDto} data - `update` 函数中的 `data` 参数表示您要为特定角色更新的新数据。它应该是 `CreateRoleDto`
   * 类型的对象，可能包含您要为具有指定 `id` 的角色更新的字段和值。
   * @returns `update` 方法返回使用 Prisma Client 更新数据库中角色的结果。
   */
  update(id: number, data: CreateRoleDto) {
    return this.prisma.role.update({
      where: {
        id,
      },
      data,
    });
  }

  /**
   * `removeMany` 函数根据提供的 ID 数组删除多个角色记录。
   * @param {number[]} ids - `ids` 参数是一个数字数组，表示需要删除的角色的 ID。`removeMany` 函数使用这些 ID 通过 Prisma 客户端的
   * `deleteMany` 方法从数据库中删除多个角色。
   * @returns `removeMany` 函数返回一个 Prisma 查询，该查询根据提供的 `ids` 数组从 `role` 表中删除多条记录。`deleteMany` 方法用于删除
   * `ids` 数组中 `id` 的记录。
   */
  removeMany(ids: number[]) {
    return this.prisma.role.deleteMany({
      where: {
        id: {
          in: ids,
        },
      },
    });
  }

  /**
   * 查找表单信息。
   * @param {number} id - 要查找的表单的唯一标识符。
   * @returns 返回一个对象，包含表单的相关信息。
   */
  findForm(id: number) {
    return this.prisma.role.findUnique({ where: { id }, select: { id: true, name: true, code: true, status: true, sort: true, dataScope: true } });
  }

  /**
   * 此 TypeScript 函数使用 Prisma 异步检索与给定角色 ID 关联的菜单 ID。
   * @param {number} id - `findMenuIds` 函数中的 `id` 参数是一个数字，表示我们要查找其关联菜单 ID 的角色 ID。该函数使用此角色 ID
   * 查询数据库并检索与该角色关联的菜单 ID 列表。
   * @returns 与提供的 roleId 对应的 menuId 数组。
   */
  async findMenuIds(id: number) {
    return (
      await this.prisma.rolesOnMenus.findMany({
        where: {
          roleId: id,
        },
        select: {
          menuId: true,
        },
      })
    ).map((item) => item.menuId);
  }

  /**
   * TypeScript 中的“updateMenus”函数通过删除现有记录并根据提供的菜单 ID 创建新记录来更新特定角色的菜单权限。
   * @param {number} id - `updateMenus` 函数中的 `id` 参数代表要更新关联菜单权限的角色的 ID。
   * @param {number[]} menuIds - `menuIds` 参数是一个数字数组，表示要与特定角色关联的菜单的 ID。在 `updateMenus` 函数中，这些菜单 ID
   * 用于更新特定角色的菜单权限。
   * @returns `updateMenus` 函数返回一个 Promise，该 Promise 解析为 Prisma 事务的结果。该事务涉及删除特定角色的所有菜单权限，然后根据为同一角色提供的
   * menuIds 数组创建新的菜单权限。
   */
  async updateMenus(id: number, menuIds: number[]) {
    return await this.prisma.$transaction([
      // 删除指定角色所有的菜单权限记录
      this.prisma.rolesOnMenus.deleteMany({ where: { roleId: id } }),
      // 根据提供的菜单ID数组，创建新的菜单权限记录
      this.prisma.rolesOnMenus.createMany({
        data: menuIds.map((menuId) => ({
          roleId: id,
          menuId: menuId,
        })),
      }),
    ]);
  }

  async findOptions() {
    const roles = await this.prisma.role.findMany({
      select: {
        id: true,
        name: true,
      },
    });
    return transformToOption(roles);
  }
}
